using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace OfficeClip.OpenSource.LogShipping
{
    public class Backup
    {
        public static void BackupDatabase(string dbName, string filePath, int backupTime, string connection, int oldBackupPreserveDays)
        {
			OpenSource.Utility.Db db = new OfficeClip.OpenSource.Utility.Db(connection, OpenSource.LogShipping.Program.Log);
            string autoFileName = string.Format(@"{0}.{1}.bak",
                        DateTime.Now.ToString("yyyyMMdd"), DateTime.Now.ToString("HHmmss"));
            // first check if a full backup is required
            if (IsFullBackupRequired(filePath, backupTime))
            {
                // first create the backup in a temporary folder
                System.CodeDom.Compiler.TempFileCollection tfc = null;
                try
                {
                    tfc = new System.CodeDom.Compiler.TempFileCollection();
                    string fileName = tfc.AddExtension("bak");
					OpenSource.LogShipping.Program.Log.WriteInfo("Database", "Backup location: " + fileName);
                    db.BackupDatabase(fileName, dbName, false);
                    PreserveAndDeleteOldBackups(filePath, oldBackupPreserveDays);
                    // Now copy this file to backup folder
                    string newFileName = string.Format(@"{0}\{1}", filePath, autoFileName);
                    File.Copy(fileName, newFileName);
                }
                catch (Exception e)
                {
					OpenSource.LogShipping.Program.Log.Write(OpenSource.Utility.LogState.Error, "Database", "Operation failed: " + e.Message);
                }
                finally
                {
                    if (tfc != null)
                        tfc.Delete();
                }
            }
            else
            {
                // Take the transactional backup
                if (backupTime > -1)
                {
                    filePath = filePath + @"\transactionlog";
                    // If the transaction log folder is not created then create it
                    if (!Directory.Exists(filePath))
                    {
                        Directory.CreateDirectory(filePath);
                    }
                    string newFileName = string.Format(@"{0}\{1}", filePath, autoFileName);
                    db.BackupTransactionLog(newFileName, dbName, "OfficeClip 7");
                }
            }

        }

        public static void PreserveAndDeleteOldBackups(string filePath, int oldBackupPreserveDays)
        {
            if (!Directory.Exists(filePath + @"\old"))
            {
                Directory.CreateDirectory(filePath + @"\old");
            }
            foreach (string file in Directory.GetFiles(filePath))
            {
                File.Move(file, filePath + @"\old\" + Path.GetFileName(file));
            }
            // Now delete any backup files that are old
            foreach (string str in Directory.GetFiles(filePath + @"\old"))
            {
                if (File.GetCreationTime(str) < DateTime.Now.AddDays(-1 * oldBackupPreserveDays))
                {
                    File.Delete(str);
                }
            }
            // Also delete all the transaction logs
            if (Directory.Exists(filePath + @"\transactionlog"))
            {
                foreach (string file in Directory.GetFiles(filePath + @"\transactionlog"))
                {
                    File.Delete(file);
                }
            }
        }
        
        public static bool IsFullBackupRequired(string filePath, int backupTime)
        {
            if (backupTime == -1) return true;
            // Check if there is any existing backup, if not, we will need to take the backup
            string[] files = Directory.GetFiles(filePath);
            if (files.Length == 0) return true;
            // Now check up if the backup file is at least 24 hours old
            string file = Path.GetFileNameWithoutExtension(files[0]);
            DateTime dt = DateTime.Parse(
                string.Format("{0}-{1}-{2}T{3}:{4}:{5}",
                file.Substring(0, 4),
                file.Substring(4, 2),
                file.Substring(6, 2),
                file.Substring(9, 2),
                file.Substring(11, 2),
                file.Substring(13, 2)
                )
                );
            if ((DateTime.Now.Ticks - dt.Ticks) > TimeSpan.TicksPerDay)
            {
                return true;
            }
            else
            {
                // Now check up if it is within one hour of the schedule time, if so then check up if within two hours no backup was taken,
                // then take a backup
                DateTime scheduleTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
                scheduleTime = scheduleTime.AddHours(backupTime);
                if (
                    ((DateTime.Now.Ticks - scheduleTime.Ticks) < TimeSpan.TicksPerHour) &&
                    ((DateTime.Now.Ticks - dt.Ticks) > 2 * TimeSpan.TicksPerHour)
                    )
                {
                    return true;
                }
            }
            return false;
        }
    }
}
